module shft_reg_cntr (
    input clk,
    input shift_ena,
    input count_ena,
    input data,
    output reg [3:0] q);

    always @(posedge clk ) begin
        if(shift_ena)
            q   <=  {q[2:0],data};
        else if(count_ena) begin
            q   <=  q - 4'd1;
        end  
    end
endmodule

module cntr_1k (
    input clk,
    input reset,
    output reg [9:0] q);

    always @(posedge clk ) begin
        if(reset | q == 10'd999)
            q   <=  10'd0;
        else begin
            q   <=  q + 10'd1;
        end  
    end
endmodule

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output [3:0] count,
    output counting,
    output done,
    input ack );

    localparam FSM_W  = 8;
    localparam FSM_W1 = FSM_W - 1'b1;

    reg [FSM_W1:0]   state;
    reg [FSM_W1:0]   nxt_state;

    localparam  IDLE        = 0;
    localparam  S_0         = 1;
    localparam  S_1         = 2;
    localparam  S_11        = 3;
    localparam  S_110       = 4;
    localparam  S_SHFT_ENA  = 5;
    localparam  WAT_CNT_FIN = 6;
    localparam  WAT_ACK     = 7;

    wire            done_counting;

    //assert signal cntr
    reg [1:0]       asrt_cntr;
    wire            asrt_cntr_add;  
    wire            asrt_cntr_clr;  

    //delay val
    wire[3:0]       dly_val;

    wire            dly_val_shft_ena;
    wire            dly_val_dec;

    //delay cntr
    wire [9:0]      dly_cntr;
    wire            dly_cntr_ena;

    //assert signal cntr
    always @(posedge clk) begin
        if(reset) begin
            asrt_cntr              <= 'b0;
        end else if(asrt_cntr_add)begin
            asrt_cntr              <= asrt_cntr + 1'b1;
        end else if(asrt_cntr_clr)begin
            asrt_cntr              <= 'b0;
        end
    end
    assign                  asrt_cntr_add  = state[S_SHFT_ENA];
    assign                  asrt_cntr_clr  = 1'b0; // cntr clear itself

    //delay cntr
    cntr_1k U_cntr_1k(
        .clk        (clk),
        .reset      (~dly_cntr_ena),
        .q          (dly_cntr)
    );
    assign                  dly_cntr_ena  = state[WAT_CNT_FIN   ];

    //delay val
    shft_reg_cntr U_shft_reg_cntr
    (
        .clk        (clk),
        .shift_ena  (dly_val_shft_ena),
        .count_ena  (dly_val_dec),
        .data       (data),
        .q          (dly_val)
    );
    assign                  dly_val_shft_ena    =   state[S_SHFT_ENA ];
    assign                  dly_val_dec         =   (dly_cntr == 16'd999 ) && ~(dly_val == 4'd0);

    assign                  done_counting       =   dly_cntr == 16'd999 && dly_val == 4'd0;

    // State transition logic (combinational)
    always @(*) begin
        nxt_state[IDLE   ]          =   1'b0; // never reach for nxt_state
        nxt_state[S_0    ]          =   (state[IDLE   ] && ~data) || (state[S_1    ] && ~data) || (state[S_0    ] && ~data) 
                            || (state[S_110   ] && ~data) || (state[WAT_ACK       ] && ack);
        nxt_state[S_1    ]          =   (state[IDLE   ] &&  data) || (state[S_0    ] &&  data);
        nxt_state[S_11   ]          =   (state[S_1    ] &&  data) || (state[S_11   ] &&  data);
        nxt_state[S_110  ]          =   (state[S_11   ] && ~data);
        nxt_state[S_SHFT_ENA ]      =   (state[S_110  ] &&  data) || (state[S_SHFT_ENA  ] && ~(asrt_cntr == 2'd3));

        nxt_state[WAT_CNT_FIN   ]   =   (state[S_SHFT_ENA] && asrt_cntr == 2'd3)
                                    || (state[WAT_CNT_FIN   ] && ~done_counting);

        nxt_state[WAT_ACK       ]   =   (state[WAT_CNT_FIN   ] && done_counting) 
                                    || (state[WAT_ACK       ] && ~ack);
    end

    // State flip-flops (sequential)
    always @(posedge clk) begin
        if(reset)
            state   <=  'b10; //SEQ_RCGN
        else begin
            state   <=  nxt_state;
        end  
    end

    //output logic
    assign  done        =   state[WAT_ACK] ;
    assign  counting    =   state[WAT_CNT_FIN];
    assign  count       =   dly_val;
endmodule